//
// BisectionMethod.cpp
// Bisection Method implementation.
//
// Author: Gabriel H. Barbuto (gbarbuto@dc.uba.ar)
//
#include <cmath>
#include <cstddef>
#include <functional>

#include "BinaryIterativeMethod.h"
#include "BisectionMethod.h"

BisectionMethod::BisectionMethod(std::function<double(double)> const &f, std::size_t const &iterations) :
BinaryIterativeMethod(iterations), _f(f)
{
}

BisectionMethod::BisectionMethod(std::function<double(double)> const &f, double const &epsilon, std::size_t const &iterations) :
BinaryIterativeMethod(epsilon, iterations), _f(f)
{
}

double BisectionMethod::operator()(std::vector<double> const &arguments)
{
	this->check(arguments);

	double x0(arguments[0]);
	double x1(arguments[1]);

	double a(std::min(x0, x1));
	double b(std::max(x0, x1));
	double c(0.0);

	double last_fa(0.0);
	double last_a(b);	// This is on purpose to make it eval the function.

	for (std::size_t iteration(0); iteration < this->max_iterations(); ++iteration)
	{
		double const d((b - a) / 2.0);
		c = a + d;
		double const f_value(this->_f(c));

		if (std::fabs(f_value) < this->epsilon())
		{
			this->iterations(iteration);
			return c;
		}

		if (last_a != a)
		{
			last_a = a;
			last_fa = this->_f(a);
		}

		// Discard expression value. Just use the side effect.
		this->sign(f_value) == this->sign(last_fa) ? a = c : b = c;
	}

	this->iterations(this->max_iterations());

	return c;
}
